#define DOHOME_LOG_LVL          DOHOME_LOG_LVL_DEBUG
#define DOHOME_LOG_TAG          "doit_product"

#include <dohome_api.h>
#include <dohome_log.h>

#include "dohome_hal_wifi.h"
#include "dohome_hal_rtc.h"

#include "doit_main.h"
#include "doit_upload.h"
#include "doit_product.h"
#include "doit_timed_task.h"

#include "doit_switch_lib.h"
#include "btn_remote_fun.h"

dohome_op_ret doit_set_switch_onoff_cancel_countdown(DOHOME_UINT8_T num, DOHOME_UINT8_T onoff);

#if (defined(CONFIG_REMOTE_CONTROL_ENABLE) && CONFIG_REMOTE_CONTROL_ENABLE == 1)
#include "dohome_hal_remote.h"
#include "btn_remote_fun.h"
#endif

#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
#include "dohome_hal_pwr_measure.h"
#endif


#if (defined(CONFIG_WOL_ENABLE) && (CONFIG_WOL_ENABLE == 1))

#include "dohome_hal_network.h"
DOHOME_STATIC DOHOME_UINT32_T hexstr_to_uint32(DOHOME_UINT8_T *str, DOHOME_UINT16_T len)
{
 	DOHOME_UINT16_T i, m, n;
	DOHOME_UINT32_T temp = 0;
	for (i = 0; i<len; i++)
	{
		if (str[i] >= 'A'&&str[i] <= 'F')
			n = str[i] - 'A' + 10;
		else if (str[i] >= 'a'&&str[i] <= 'f')
			n = str[i] - 'a' + 10;
		else n = str[i] - '0';
		temp = temp * 16 + n;
	}
	return temp;
}


DOHOME_STATIC dohome_op_ret doit_product_wol(DOHOME_CHAR_T *dev){
    DOHOME_CHAR_T magic_packet[102];
    DOHOME_CHAR_T tmp_mac[6];
    dohome_upd_dest_t dest;
    DOHOME_LOG_D("WAKE ON LAN");
    if (dev == NULL || strlen(dev) <= 13 || dev[12]!=':')
    {
        return OPRT_INVALID_PARM;
    }
    for (DOHOME_UINT8_T i = 0; i < 6; i++)
    {
        tmp_mac[i] = hexstr_to_uint32(&dev[2*i], 2);
    }
    dest.ip_type = DOHOME_IP_TYPE_IPv4;
    dest.port = atoi(dev+13);
    dest.addr.ip_v4.addr = 0xffffffff;
    memset(magic_packet, 0xff, 6);
    for (DOHOME_UINT8_T i = 1; i <= 16; i++)
    {
        memcpy((magic_packet+i*6), tmp_mac, sizeof(tmp_mac));
    }
    extern dohome_op_ret dohome_udp_send(dohome_upd_dest_t dest, DOHOME_CHAR_T *data, DOHOME_UINT16_T len);
    dohome_udp_send(dest, magic_packet, sizeof(magic_packet));
    dohome_udp_send(dest, magic_packet, sizeof(magic_packet));
    dohome_udp_send(dest, magic_packet, sizeof(magic_packet));
    return OPRT_OK;
}
#endif


#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)

void power_measure_loop(void){

    DOHOME_STATIC DOHOME_UINT8_T save_flag = 0;
    DOHOME_STATIC DOHOME_UINT8_T reset_flag = 0;
    DOHOME_STATIC DOHOME_UINT8_T compensate_flag = 0;
    DOHOME_STATIC DOHOME_UINT32_T last_energy_Wh = 0;

    DOHOME_UINT32_T time = 0;
    DOHOME_UINT32_T energy_Wh = 0;
    DOHOME_UINT32_T energy_Ws = 0;


    DOHOME_UINT8_T dpid_list[1] = {PRODUCT_ADD_ELE};
    
    time = dohome_hal_rtc_get_time();
    if(time > 1627289170){
        if(time%86400 == 0 && reset_flag == 0){
            reset_flag = 1;
            compensate_flag = 1;
            last_energy_Wh = 0;
            dohome_hal_pwr_measure_reset_power_energy();
            doit_product_save_status();
        }else{
            reset_flag = 0;
        }

        if(compensate_flag == 0){
            compensate_flag = 1;
            doit_product_status_t product_status = {0};
            doit_product_read_status(&product_status);
            if(time/86400 == product_status.energy_timestamp/86400){
                energy_Ws = dohome_hal_pwr_measure_get_power_energy_Ws();
                dohome_hal_pwr_measure_set_power_energy_Ws(product_status.energy_compensate + energy_Ws);
                doit_product_save_status();
            }
        }else{
            energy_Wh = dohome_hal_pwr_measure_get_power_energy_Wh();
            if(energy_Wh - last_energy_Wh > 100){
                last_energy_Wh = energy_Wh;
                dohome_cloud_post_dps(dpid_list, 1);

                doit_product_save_status();
            }
            if(save_flag == 0 && energy_Wh - last_energy_Wh == 50){
                doit_product_save_status();
                save_flag = 1;
            }else{
                save_flag = 0;
            }
        }
    }
}


void power_measure_fault_cb(dohome_pwr_measure_fault_t fault){
    DOHOME_LOG_I("power_measure_fault_cb: %d", fault);

    switch (fault)
    {
    case DOHOME_PWR_MEASURE_FAULT_SET_HIGH_CURRENT:
        doit_set_switch_onoff_cancel_countdown(0, 0);
        break;
    case DOHOME_PWR_MEASURE_FAULT_CLS_HIGH_CURRENT:
        /* code */  
        break;
    
    default:
        break;
    }
}


dohome_op_ret power_measure_set_overcurrent_protection(DOHOME_UINT8_T en){
    dohome_pwr_measure_fault_cfg_t fault_cfg = {0};
    
    // dohome_hal_pwr_measure_get_fault_cfg(&fault_cfg);
    memset(&fault_cfg, 0, sizeof(dohome_pwr_measure_fault_cfg_t));

    if(en){
        fault_cfg.high_current_en = 1;
        fault_cfg.high_current_value = CONFIG_POWER_MEASURE_OVERCURRENT_VALUE;
    }
    

    dohome_hal_pwr_measure_set_fault_cfg(fault_cfg);
    return OPRT_OK;
}

DOHOME_UINT8_T power_measure_get_overcurrent_protection(void){
    dohome_pwr_measure_fault_cfg_t fault_cfg;
    dohome_hal_pwr_measure_get_fault_cfg(&fault_cfg);
    return fault_cfg.high_current_en;
}

#endif

void doit_post_countdown_dps(DOHOME_UINT8_T num){
    DOHOME_CHAR_T dpid_list[1] = {0};

    switch (num)
    {
    case 0:
        dpid_list[0] = PRODUCT_SWITCH1_COUNTDOWN;
        break;
    case 1:
        dpid_list[0] = PRODUCT_SWITCH2_COUNTDOWN;
        break;
    case 2:
        dpid_list[0] = PRODUCT_SWITCH3_COUNTDOWN;
        break;
    case 3:
        dpid_list[0] = PRODUCT_SWITCH4_COUNTDOWN;
        break;
    case 4:
        dpid_list[0] = PRODUCT_SWITCH5_COUNTDOWN;
        break;
    case 5:
        dpid_list[0] = PRODUCT_SWITCH6_COUNTDOWN;
        break;
    case 6:
        dpid_list[0] = PRODUCT_SWITCH7_COUNTDOWN;
        break;
    case 7:
        dpid_list[0] = PRODUCT_SWITCH8_COUNTDOWN;
        break;
    default:
        return;
        break;
    }
    // dohome_cloud_post_dps(dpid_list, 1);
    doit_upload_cmd_now(dpid_list[0]);
}


//设置开关 有倒计时则取消倒计时
dohome_op_ret doit_set_switch_onoff_cancel_countdown(DOHOME_UINT8_T num, DOHOME_UINT8_T onoff){
    if(doit_switch_get_onoff(num) != onoff){
        if(doit_reset_countdown(num) == OPRT_OK){
            doit_post_countdown_dps(num);
        }
    }
    return doit_switch_set_onoff(num, onoff);
}

dohome_op_ret doit_product_get_dps(dh_obj_dps_t *dps){

    DOHOME_UINT8_T i = 0, j= 0;
    DOHOME_UINT8_T bit_value = 0;
    DOHOME_UINT8_T switch_value = 0;
    dohome_op_ret ret = OPRT_COM_ERROR;
    for (i = 0; i < dps->dps_cnt ; i++)
    {
        DOHOME_LOG_D("get dpid: %d", dps->dps_list[i].dpid);
        switch (dps->dps_list[i].dpid)
        {
        case PRODUCT_SWITCH_ONOFF:
            dps->dps_list[i].type = DP_TP_VALUE;
            switch_value = 0; 
            for (j = 0; j < CONFIG_SWITCH_NUM; j++){
                bit_value = 0;
                if (doit_switch_get_onoff(j)){
                    bit_value = 1 << j;
                }
                switch_value |= bit_value;
                // DOHOME_LOG_D("switch_value: %08x\n", switch_value);
            }
            DOHOME_LOG_D("switch_value: %08x\n", switch_value);
            dps->dps_list[i].value.dp_value = switch_value;
            DOHOME_LOG_D("get dpid: %d value: %d\n", dps->dps_list[i].dpid, dps->dps_list[i].value.dp_value);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH1_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(0);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH2_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(1);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH3_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(2);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH4_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(3);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH5_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(4);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH6_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(5);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH7_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(6);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH8_COUNTDOWN:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_get_countdown(7);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH1_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(0);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH2_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(1);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH3_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(2);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH4_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(3);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH5_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(4);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH6_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(5);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH7_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(6);
            ret = OPRT_OK;
        break;
        case PRODUCT_SWITCH8_NORMAL_TIME:
            dps->dps_list[i].type = DP_TP_STR;
            dps->dps_list[i].value.dp_str = doit_get_timer_str(7);
            ret = OPRT_OK;
        break;
        case PRODUCT_RELAY_STATUS:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_switch_get_boot_state();
            ret = OPRT_OK;
        break;
        case PRODUCT_LED_STATUS:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = doit_switch_get_led_state();
            ret = OPRT_OK;
        break; 
#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
        case PRODUCT_CUR_VOLTAGE:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = dohome_hal_pwr_measure_get_voltage_V();
            ret = OPRT_OK;
        break;
        case PRODUCT_CUR_CURRENT:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = dohome_hal_pwr_measure_get_current_mA();
            ret = OPRT_OK;
        break;
        case PRODUCT_CUR_POWER:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = dohome_hal_pwr_measure_get_active_power_W();
            ret = OPRT_OK;
        break;
        case PRODUCT_ADD_ELE:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = (dohome_hal_pwr_measure_get_power_energy_Wh()/100)*100;
            ret = OPRT_OK;
        break;
        case PRODUCT_OVER_CURRENT_PROTECTION:
            dps->dps_list[i].type = DP_TP_VALUE;
            dps->dps_list[i].value.dp_value = power_measure_get_overcurrent_protection();
            ret = OPRT_OK;
        break;
#endif
        default:
            break;
        }
        if(dps->dps_list[i].type == DP_TP_VALUE){
            DOHOME_LOG_D("get dpid: %d value: %d", dps->dps_list[i].dpid, dps->dps_list[i].value.dp_value);
        }else if(dps->dps_list[i].type == DP_TP_STR)
        {
            DOHOME_LOG_D("get dpid: %d value: %s", dps->dps_list[i].dpid, dps->dps_list[i].value.dp_str);
        }
        
    }
    return ret;
}

dohome_op_ret doit_product_get_all_dps(dh_obj_dps_t *dps){

#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
    DOHOME_UINT8_T all_table[] = {PRODUCT_SWITCH_ONOFF COUNTDOWN_DPID_1 COUNTDOWN_DPID_2 COUNTDOWN_DPID_3 COUNTDOWN_DPID_4 COUNTDOWN_DPID_5 COUNTDOWN_DPID_6 COUNTDOWN_DPID_7 COUNTDOWN_DPID_8, PRODUCT_ADD_ELE, PRODUCT_CUR_POWER};
#else
    DOHOME_UINT8_T all_table[] = {PRODUCT_SWITCH_ONOFF COUNTDOWN_DPID_1 COUNTDOWN_DPID_2 COUNTDOWN_DPID_3 COUNTDOWN_DPID_4 COUNTDOWN_DPID_5 COUNTDOWN_DPID_6 COUNTDOWN_DPID_7 COUNTDOWN_DPID_8};
#endif   
    DOHOME_UINT8_T i = 0;
    dps->dps_cnt = sizeof(all_table)/sizeof(all_table[0]);
    for (i = 0; i < dps->dps_cnt ; i++){
        dps->dps_list[i].dpid = all_table[i];
    }
    return doit_product_get_dps(dps);
}


dohome_op_ret doit_product_set_dps(dh_obj_dps_t *dps, DOHOME_UINT8_T *cancel_resp){

    DOHOME_UINT8_T i = 0, j = 0;
    DOHOME_UINT8_T bit_value = 0;
    DOHOME_UINT8_T switch_value = 0;
    DOHOME_UINT8_T on = 0;
    dohome_op_ret ret = OPRT_COM_ERROR;
    for (i = 0; i < dps->dps_cnt; i++)
    {
        if(dps->dps_list[i].type == DP_TP_VALUE){
            DOHOME_LOG_D("pdid: %d    data: %d", dps->dps_list[i].dpid, dps->dps_list[i].value.dp_value);
            switch (dps->dps_list[i].dpid)
            {
            case PRODUCT_SWITCH_ONOFF:
                bit_value = 0;
                switch_value = dps->dps_list[i].value.dp_value;
                DOHOME_LOG_D("switch_value: %d\n", switch_value);
                for (j = 0; j < CONFIG_SWITCH_NUM; j++){
                    bit_value = 1 << j;
                    on = (switch_value&bit_value)?1:0;
                    DOHOME_LOG_D("set %d onoff: %d\n", j, on);
                    ret = doit_set_switch_onoff_cancel_countdown(j, on);
                    if(ret != OPRT_OK){
                        break;
                    }
                }
            break;
            case PRODUCT_SWITCH1_COUNTDOWN:
                ret = doit_set_countdown(0, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_SWITCH2_COUNTDOWN:
                ret = doit_set_countdown(1, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_SWITCH3_COUNTDOWN:
                ret = doit_set_countdown(2, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_SWITCH4_COUNTDOWN:
                ret = doit_set_countdown(3, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_SWITCH5_COUNTDOWN:
                ret = doit_set_countdown(4, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_SWITCH6_COUNTDOWN:
                ret = doit_set_countdown(5, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_SWITCH7_COUNTDOWN:
                ret = doit_set_countdown(6, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_SWITCH8_COUNTDOWN:
                ret = doit_set_countdown(7, dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_RELAY_STATUS:
                ret = doit_switch_set_boot_state(dps->dps_list[i].value.dp_value);
            break;
            case PRODUCT_LED_STATUS:
                ret = doit_switch_set_led_state(dps->dps_list[i].value.dp_value);
            break;
#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
            case PRODUCT_OVER_CURRENT_PROTECTION:
                ret = power_measure_set_overcurrent_protection(dps->dps_list[i].value.dp_value);
            break;
#endif
            default:
                break;
            }
        }else if(dps->dps_list[i].type == DP_TP_STR){
            // DOHOME_LOG_D("pdid: %d    data: %s", dps->dps_list[i].dpid, dps->dps_list[i].value.dp_str);
            switch (dps->dps_list[i].dpid)
            {
#if (defined(CONFIG_WOL_ENABLE) && (CONFIG_WOL_ENABLE == 1))
            case PRODUCT_WAKE_ON_LAN:
                ret = doit_product_wol(dps->dps_list[i].value.dp_str);
                return ret;
            break;
#endif
            case PRODUCT_SWITCH1_NORMAL_TIME:
                ret = doit_set_timer_to_str(0, dps->dps_list[i].value.dp_str);
            break;
            case PRODUCT_SWITCH2_NORMAL_TIME:
                ret = doit_set_timer_to_str(1, dps->dps_list[i].value.dp_str);
            break;
            case PRODUCT_SWITCH3_NORMAL_TIME:
                ret = doit_set_timer_to_str(2, dps->dps_list[i].value.dp_str);
            break;
            case PRODUCT_SWITCH4_NORMAL_TIME:
                ret = doit_set_timer_to_str(3, dps->dps_list[i].value.dp_str);
            break;
            case PRODUCT_SWITCH5_NORMAL_TIME:
                ret = doit_set_timer_to_str(4, dps->dps_list[i].value.dp_str);
            break;
            case PRODUCT_SWITCH6_NORMAL_TIME:
                ret = doit_set_timer_to_str(5, dps->dps_list[i].value.dp_str);
            break;
            case PRODUCT_SWITCH7_NORMAL_TIME:
                ret = doit_set_timer_to_str(6, dps->dps_list[i].value.dp_str);
            break;
            case PRODUCT_SWITCH8_NORMAL_TIME:
                ret = doit_set_timer_to_str(7, dps->dps_list[i].value.dp_str);
            break;

            default:
                break;
            }
        }
    }

    *cancel_resp = 0;

    doit_update_staus_delay();

    return ret;
}


dohome_op_ret doit_product_save_status(void){

    DOHOME_UINT8_T i = 0;
    doit_product_status_t product_status = {0};
    product_status.boot_state = doit_switch_get_boot_state();
    doit_switch_get_all_onoff((dt_switch_power_t *)&product_status.switch_list);

    DOHOME_LOG_I("doit_product_save_status  boot_state: %d", product_status.boot_state);
    for (i = 0; i < CONFIG_SWITCH_NUM; i++){
        DOHOME_LOG_I("doit_product_save_status  switch%d: %d", i+1, product_status.switch_list[i].onoff);
    }

    product_status.led_state = doit_switch_get_led_state();

#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
    product_status.energy_timestamp = dohome_hal_rtc_get_time();
    product_status.energy_compensate = dohome_hal_pwr_measure_get_power_energy_Ws();
    product_status.overcurrent_en = power_measure_get_overcurrent_protection();
    DOHOME_LOG_I("save_energy_compensate: %d", product_status.energy_compensate);
#endif
    
    dohome_kvs_set_env_blob("dt_pd_state", &product_status, sizeof(doit_product_status_t));
    return OPRT_OK;
}

dohome_op_ret doit_product_default_status(doit_product_status_t *status){
    DOHOME_UINT8_T i = 0;
#if CONFIG_DEFAULT_POWER_ON_MEMORY
    status->boot_state = DT_SWITCH_BOOT_MEMORY;
#else
    status->boot_state = DT_SWITCH_BOOT_OFF;
#endif

    status->led_state = DT_SWITCH_LED_RELAY;

    // for (i = 0; i < CONFIG_SWITCH_NUM; i++){
    //     status->switch_list[i].onoff = 0;
    // }

#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
    status->energy_compensate = 0;
    status->overcurrent_en = CONFIG_POWER_MEASURE_OVERCURRENT_ENABLE;
#endif
    return OPRT_OK;
}

dohome_op_ret doit_product_write_status(doit_product_status_t status){

    dohome_kvs_set_env_blob("dt_pd_state", &status, sizeof(doit_product_status_t));
    return OPRT_OK;
}

dohome_op_ret doit_product_read_status(doit_product_status_t *status){

    DOHOME_UINT8_T i = 0;
    DOHOME_SIZE_T len = 0;
    len = dohome_kvs_get_env_blob("dt_pd_state", status, sizeof(doit_product_status_t), NULL);
    if(len != sizeof(doit_product_status_t)){
        for (i = 0; i < CONFIG_SWITCH_NUM; i++){
            status->switch_list[i].onoff = 0;
        }
        doit_product_default_status(status);
    }
    DOHOME_LOG_D("doit_product_read_status  boot_state: %d\n", status->boot_state);
    for (i = 0; i < CONFIG_SWITCH_NUM; i++){
        if(status->switch_list[i].onoff > 1){
            status->switch_list[i].onoff = 0;
        }
        DOHOME_LOG_D("doit_product_read_status  switch%d: %d\n", i+1, status->switch_list[i].onoff);
    }
    return OPRT_OK;
}

void doit_product_status_init(void){
    doit_product_status_t product_status = {0};
    memset(&product_status, 0, sizeof(product_status));

    doit_product_read_status(&product_status);

    doit_switch_set_led_state(product_status.led_state);
    
    doit_switch_set_boot_onoff(product_status.switch_list, product_status.boot_state);

#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
    power_measure_set_overcurrent_protection(product_status.overcurrent_en);
#endif
}


void doit_countdown_task_cb(DOHOME_UINT8_T num){
    DOHOME_LOG_I("doit_countdown_task_cb: %d reverse_onoff", num);
    doit_switch_reverse(num);
    doit_update_staus_now();

    doit_post_countdown_dps(num);
}

void doit_timed_task_cb(DOHOME_UINT8_T num, DOHOME_UINT8_T onoff){
    DOHOME_LOG_I("doit_timer_task_cb: %d  onoff: %d", num, onoff);
    doit_set_switch_onoff_cancel_countdown(num, onoff);
    doit_update_staus_now();

    DOHOME_UINT8_T dpid_list[1] = {0};

    switch (num)
    {
    case 0:
        dpid_list[0] = PRODUCT_SWITCH1_NORMAL_TIME;
        break;
    case 1:
        dpid_list[0] = PRODUCT_SWITCH2_NORMAL_TIME;
        break;
    case 2:
        dpid_list[0] = PRODUCT_SWITCH3_NORMAL_TIME;
        break;
    case 3:
        dpid_list[0] = PRODUCT_SWITCH4_NORMAL_TIME;
        break;
    case 4:
        dpid_list[0] = PRODUCT_SWITCH5_NORMAL_TIME;
        break;
    case 5:
        dpid_list[0] = PRODUCT_SWITCH6_NORMAL_TIME;
        break;
    case 6:
        dpid_list[0] = PRODUCT_SWITCH7_NORMAL_TIME;
        break;
    case 7:
        dpid_list[0] = PRODUCT_SWITCH8_NORMAL_TIME;
        break;
    default:
        return;
        break;
    }
    dohome_cloud_post_dps(dpid_list, 1);
}

DOHOME_STATIC void keys_event_cb(void *arg){

	flex_button_t *btn = (flex_button_t *)arg;

    DOHOME_LOG_I("id: [%d]  event: [%d]  repeat: %d", btn->id, btn->event, btn->click_cnt);

    DOHOME_UINT8_T switch_id = 0, i = 0; 
    doit_switch_btn_id_to_switch_id(btn->id, &switch_id);

    if(btn->event == FLEX_BTN_PRESS_CLICK){

        if(switch_id < CONFIG_SWITCH_NUM){
            if(doit_reset_countdown(switch_id) == OPRT_OK){
                doit_post_countdown_dps(switch_id);
            }
        }else if(switch_id == DT_ALL_SWITCH_ID){
            for (i = 0; i < CONFIG_SWITCH_NUM; i++){
                doit_reset_countdown(i);
            }
            
        }
    }

    BTN_FUN_EXECUTION(btn->event, btn->id);

#if (defined(CONFIG_REMOTE_CONTROL_ENABLE) && CONFIG_REMOTE_CONTROL_ENABLE == 1)
#if ((CONFIG_REMOTE_CONTROL_WAY == CONFIG_REMOTE_CONTROL_WAY_RF) && (CONFIG_REMOTE_CONTROL_MODEL == CONFIG_REMOTE_CONTROL_MODEL_RF_4_1))
    if(switch_id < CONFIG_SWITCH_NUM){
        btn_remote_rf_4_1_key_cb(switch_id, btn->event, btn->click_cnt);
    }
#endif
#endif

    doit_update_staus_now();
}

#if ((DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFI) || (DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFIBLE))
void doit_product_wifi_connect_status(void){
    DOHOME_LOG_I("wifi_connect");
    if(doit_switch_wifi_led_is_flash()){
        doit_switch_wifi_led_stop_flash();
    }
    doit_switch_wifi_led_set_status(1);
}


void doit_product_wifi_disconnect_status(void){
    doit_switch_wifi_led_set_status(0);
}

void doit_product_wifi_config_status(DOHOME_UINT8_T status){
    DOHOME_LOG_I("wifi_config %s", status?"sueecs":"fail");

    if(doit_switch_wifi_led_is_flash()){
        doit_switch_wifi_led_stop_flash();
    }
    if(status == 0 && dohome_wifi_has_config()){
        dohome_wifi_start_connect();
    }
}
#elif (DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_BLE)
void doit_product_ble_connect_status(void){
	
}

void doit_product_ble_disconnect_status(void){
    
}

void doit_product_ble_config_status(DOHOME_UINT8_T status){
    DOHOME_LOG_I("ble_config %s", status?"sueecs":"fail");

    doit_switch_wifi_led_stop_flash();
}
#endif

void doit_product_start_config_status(void){
    doit_product_default_boot_status();
    DOHOME_LOG_I("start_wifi_config");
    doit_switch_wifi_led_start_flash();
}

void doit_product_default_boot_status(void){

    // doit_product_status_t product_status = {0};
    // doit_product_read_status(&product_status);
    
    // doit_switch_set_boot_onoff(product_status.switch_list, product_status.boot_state);
}

void doit_product_factory_reset_status(void){
    doit_product_status_t status = {0};
    memset(&status, 0, sizeof(status));

    doit_product_read_status(&status);
    doit_product_default_status(&status);
    doit_product_write_status(status);

    doit_switch_set_led_state(status.led_state);
    doit_switch_set_boot_state(status.boot_state);
#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
    power_measure_set_overcurrent_protection(status.overcurrent_en);
#endif

    doit_reset_timed_task();
}

void doit_product_task_loop(void){

    DOHOME_STATIC DOHOME_UINT64_T loop_tick_ms = 0;

    doit_switch_button_scan();

    if(loop_tick_ms%500 == 0){
		doit_switch_wifi_led_flash_loop();
    }

#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)

    if(loop_tick_ms%100 == 0){
        power_measure_loop();
    } 

    // if(loop_tick_ms%1000 == 0){
    //     printf("[PWR] %d, %d, %d, %d, %d\n", dohome_hal_pwr_measure_get_voltage_V(), dohome_hal_pwr_measure_get_current_mA(), dohome_hal_pwr_measure_get_active_power_W(), dohome_hal_pwr_measure_get_power_energy_Ws(), dohome_hal_pwr_measure_get_power_energy_Wh());  
    // }  
#endif

#if (defined(CONFIG_REMOTE_CONTROL_ENABLE) && CONFIG_REMOTE_CONTROL_ENABLE == 1)
#if ((CONFIG_REMOTE_CONTROL_WAY == CONFIG_REMOTE_CONTROL_WAY_RF) && (CONFIG_REMOTE_CONTROL_MODEL == CONFIG_REMOTE_CONTROL_MODEL_RF_4_1))
    if(loop_tick_ms%100 == 0){
        btn_remote_rf_4_1_loop();
    }
#endif
#endif

    loop_tick_ms += DOIT_LOOP_PERIOD;
    loop_tick_ms = (loop_tick_ms)%(3600000);
}

dohome_op_ret doit_product_set_dps_cb(dh_obj_dps_t *dps, DOHOME_UINT8_T *cancel_resp){
    return doit_product_set_dps(dps, cancel_resp);
}

dohome_op_ret doit_product_get_dps_cb(DOHOME_CHAR_T all, dh_obj_dps_t *dps){

    if(all == 1){
        return doit_product_get_all_dps(dps);
    }else{
        return doit_product_get_dps(dps);
    }
}

void dohome_system_event_handler(dohome_event_type_t event_type, DOHOME_UINT16_T event_id, void* event_data){
    if(event_type == DOHOME_SYSTEM_EVENT){
        DOHOME_LOG_I("event_type: DOHOME_SYSTEM_EVENT, event_id: %d\n", event_id);
        if(event_id == DOHOME_SYSTEM_EVENT_FACTORY_RESET){
#if CONFIG_USE_POWER_SWITCH_CONFIG        
            doit_res_reset_cnt();
#endif
            doit_product_factory_reset_status();
        }
    }
} 

#if ((DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFI) || (DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFIBLE))
void dohome_wifi_event_handler(dohome_event_type_t event_type, DOHOME_UINT16_T event_id, void* event_data){
    if(event_type == DOHOME_WIFI_EVENT){
        DOHOME_LOG_I("event_type: DOHOME_WIFI_EVENT, event_id: %d\n", event_id);
        switch (event_id)
        {
        case DOHOME_WIFI_EVENT_STA_CONNECT:
            doit_product_wifi_connect_status();
            break;
        case DOHOME_WIFI_EVENT_STA_DISCONNECT:
            doit_product_wifi_disconnect_status();
            break;
        case DOHOME_WIFI_EVENT_CFG_START:
            doit_product_start_config_status();
            break;
        case DOHOME_WIFI_EVENT_CFG_FAIL:
            doit_product_wifi_config_status(0);
            break;
        case DOHOME_WIFI_EVENT_CFG_SUCCESS:
            doit_product_wifi_config_status(1);
            break;
        default:
            break;
        }
    }
} 
#elif (DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_BLE)
void dohome_ble_event_handler(dohome_event_type_t event_type, DOHOME_UINT16_T event_id, void* event_data){
    DOHOME_UINT8_T mode = 0;
    
    if(event_type == DOHOME_BLE_EVENT){
        switch (event_id)
        {
        case DOHOME_BLE_EVENT_STA_CONNECT:
            doit_product_ble_connect_status();
            break;
        case DOHOME_BLE_EVENT_STA_DISCONNECT:
            doit_product_ble_disconnect_status();
            break;
        case DOHOME_BLE_EVENT_CFG_START:
            
            //不是首次配网才开启配网状态(首次配网状态已经由main先行开启)
            doit_product_start_config_status();
            
            break;
        case DOHOME_BLE_EVENT_CFG_FAIL:
            doit_product_ble_config_status(0);
            break;
        case DOHOME_BLE_EVENT_CFG_SUCCESS:
            doit_product_ble_config_status(1);
            break;
        default:
            break;
        }
    }
}
#endif


void doit_product_register_cb(void){
#if ((DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFI) || (DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_WIFIBLE))
    dohome_event_reg_handler(DOHOME_WIFI_EVENT, dohome_wifi_event_handler);
#elif (DOHOME_PLATFORM_TYPE == DOHOME_PLATFORM_BLE)
    dohome_event_reg_handler(DOHOME_BLE_EVENT, dohome_ble_event_handler);
#endif

    dohome_event_reg_handler(DOHOME_SYSTEM_EVENT, dohome_system_event_handler);

    dohome_cloud_reg_set_dps_cb(doit_product_set_dps_cb);
    dohome_cloud_reg_get_dps_cb(doit_product_get_dps_cb);
}

void doit_product_init(void){

    doit_switch_init(keys_event_cb);

#if (defined(CONFIG_POWER_MEASURE_ENABLE) && CONFIG_POWER_MEASURE_ENABLE == 1)
    dohome_pwr_measure_cfg_t cfg = {.type = DOHOME_PWR_MEASURE_TYPE_MAX}; 

#if (CONFIG_POWER_MEASURE_TYPE == POWER_MEASURE_TYPE_HLW8012)
    cfg.type = DOHOME_PWR_MEASURE_TYPE_HLW8012;
    cfg.ic.hlw8012.fc_gpio = CONFIG_POWER_MEASURE_CF_GPIO;
    cfg.ic.hlw8012.fc1_gpio = CONFIG_POWER_MEASURE_CF1_GPIO;
    cfg.ic.hlw8012.sel_gpio = CONFIG_POWER_MEASURE_SEL_GPIO;
    
    memset(&cfg.fault_cfg, 0, sizeof(dohome_pwr_measure_fault_cfg_t));
#elif (CONFIG_POWER_MEASURE_TYPE == POWER_MEASURE_TYPE_BL0937)
    cfg.type = DOHOME_PWR_MEASURE_TYPE_BL0937;
    cfg.ic.bl0937.fc_gpio = CONFIG_POWER_MEASURE_CF_GPIO;
    cfg.ic.bl0937.fc1_gpio = CONFIG_POWER_MEASURE_CF1_GPIO;
    cfg.ic.bl0937.sel_gpio = CONFIG_POWER_MEASURE_SEL_GPIO;

    memset(&cfg.fault_cfg, 0, sizeof(dohome_pwr_measure_fault_cfg_t));
#endif

    dohome_hal_pwr_measure_init(cfg, power_measure_fault_cb);

#ifdef CONFIG_POWER_MEASURE_DEFAULT_VOLTAGE_CAL
    dohome_hal_pwr_measure_set_default_voltage_cal(CONFIG_POWER_MEASURE_DEFAULT_VOLTAGE_CAL);
#endif
#ifdef CONFIG_POWER_MEASURE_DEFAULT_CURRENT_CAL
    dohome_hal_pwr_measure_set_default_current_cal(CONFIG_POWER_MEASURE_DEFAULT_CURRENT_CAL);
#endif
#ifdef CONFIG_POWER_MEASURE_DEFAULT_POWER_CAL
    dohome_hal_pwr_measure_set_default_power_cal(CONFIG_POWER_MEASURE_DEFAULT_POWER_CAL);
#endif

#endif

    doit_product_status_init();

    doit_timed_task_init();

    doit_timed_task_set_cb(doit_timed_task_cb);
    doit_countdown_task_set_cb(doit_countdown_task_cb);

#if (defined(CONFIG_REMOTE_CONTROL_ENABLE) && CONFIG_REMOTE_CONTROL_ENABLE == 1)
#if (CONFIG_REMOTE_CONTROL_WAY == CONFIG_REMOTE_CONTROL_WAY_RF)
#if (CONFIG_REMOTE_CONTROL_MODEL == CONFIG_REMOTE_CONTROL_MODEL_RF_4_1)
    btn_remote_rf_4_1_init();
#endif
#endif
#endif

}